1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import sun.management.jmxremote.ConnectorBootstrap;
24
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.InputStream;
28 import java.io.FilenameFilter;
29 import java.io.IOException;
30
31 import java.util.Properties;
32 import java.util.Iterator;
33 import java.util.Set;
34 import java.util.Arrays;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.Map;
38 import java.util.Enumeration;
39
40 import javax.management.remote.*;
41 import javax.management.*;
42
43 import sun.management.AgentConfigurationError;
44
45 import util.TestLogger;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class RmiBootstrapTest {
72
73 static TestLogger log =
74 new TestLogger("RmiBootstrapTest");
75
76
77
78
79
80 static int testPort = 0;
81
82
83
84
85 public static interface DefaultValues {
86 public static final String PORT="0";
87 public static final String CONFIG_FILE_NAME="management.properties";
88 public static final String USE_SSL="true";
89 public static final String USE_AUTHENTICATION="true";
90 public static final String PASSWORD_FILE_NAME="jmxremote.password";
91 public static final String ACCESS_FILE_NAME="jmxremote.access";
92 public static final String KEYSTORE="keystore";
93 public static final String KEYSTORE_PASSWD="password";
94 public static final String TRUSTSTORE="truststore";
95 public static final String TRUSTSTORE_PASSWD="trustword";
96 public static final String SSL_NEED_CLIENT_AUTH="false";
97 }
98
99
100
101
102 public static interface PropertyNames {
103 public static final String PORT=
104 "com.sun.management.jmxremote.port";
105 public static final String CONFIG_FILE_NAME=
106 "com.sun.management.config.file";
107 public static final String USE_SSL=
108 "com.sun.management.jmxremote.ssl";
109 public static final String USE_AUTHENTICATION=
110 "com.sun.management.jmxremote.authenticate";
111 public static final String PASSWORD_FILE_NAME=
112 "com.sun.management.jmxremote.password.file";
113 public static final String ACCESS_FILE_NAME=
114 "com.sun.management.jmxremote.access.file";
115 public static final String INSTRUMENT_ALL=
116 "com.sun.management.instrumentall";
117 public static final String CREDENTIALS =
118 "jmx.remote.credentials";
119 public static final String KEYSTORE=
120 "javax.net.ssl.keyStore";
121 public static final String KEYSTORE_PASSWD=
122 "javax.net.ssl.keyStorePassword";
123 public static final String TRUSTSTORE=
124 "javax.net.ssl.trustStore";
125 public static final String TRUSTSTORE_PASSWD=
126 "javax.net.ssl.trustStorePassword";
127 public static final String SSL_ENABLED_CIPHER_SUITES =
128 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
129 public static final String SSL_ENABLED_PROTOCOLS =
130 "com.sun.management.jmxremote.ssl.enabled.protocols";
131 public static final String SSL_NEED_CLIENT_AUTH =
132 "com.sun.management.jmxremote.ssl.need.client.auth";
133 }
134
135
136
137
138
139 private static class ConfigFilenameFilter implements FilenameFilter {
140 final String suffix;
141 final String prefix;
142 ConfigFilenameFilter(String prefix, String suffix) {
143 this.suffix=suffix;
144 this.prefix=prefix;
145 }
146 public boolean accept(File dir, String name) {
147 return (name.startsWith(prefix) && name.endsWith(suffix));
148 }
149 }
150
151
152
153
154
155 private static File[] findConfigurationFilesOk() {
156 final String testSrc = System.getProperty("test.src");
157 final File dir = new File(testSrc);
158 final FilenameFilter filter =
159 new ConfigFilenameFilter("management_test","ok.properties");
160 return dir.listFiles(filter);
161 }
162
163
164
165
166
167 private static File[] findConfigurationFilesKo() {
168 final String testSrc = System.getProperty("test.src");
169 final File dir = new File(testSrc);
170 final FilenameFilter filter =
171 new ConfigFilenameFilter("management_test","ko.properties");
172 return dir.listFiles(filter);
173 }
174
175
176
177
178
179
180 public static int listMBeans(MBeanServerConnection server)
181 throws IOException {
182 return listMBeans(server,null,null);
183 }
184
185
186
187
188
189
190 public static int listMBeans(MBeanServerConnection server,
191 ObjectName pattern, QueryExp query)
192 throws IOException {
193
194 final Set names = server.queryNames(pattern,query);
195 for (final Iterator i=names.iterator(); i.hasNext(); ) {
196 ObjectName name = (ObjectName)i.next();
197 log.trace("listMBeans","Got MBean: "+name);
198 try {
199 MBeanInfo info =
200 server.getMBeanInfo((ObjectName)name);
201 MBeanAttributeInfo[] attrs = info.getAttributes();
202 if (attrs == null) continue;
203 for (int j=0; j<attrs.length; j++) {
204 if (attrs[j].isReadable()) {
205 try {
206 Object o =
207 server.getAttribute(name,attrs[j].getName());
208 if (log.isDebugOn())
209 log.debug("listMBeans","\t\t" +
210 attrs[j].getName() +
211 " = "+o);
212 } catch (Exception x) {
213 log.trace("listMBeans","JmxClient failed to get " +
214 attrs[j].getName() + ": " + x);
215 final IOException io =
216 new IOException("JmxClient failed to get " +
217 attrs[j].getName());
218 io.initCause(x);
219 throw io;
220 }
221 }
222 }
223 } catch (Exception x) {
224 log.trace("listMBeans",
225 "JmxClient failed to get MBeanInfo: " + x);
226 final IOException io =
227 new IOException("JmxClient failed to get MBeanInfo: "+x);
228 io.initCause(x);
229 throw io;
230 }
231 }
232 return names.size();
233 }
234
235
236
237
238
239
240 private static String getDefaultFileName(String basename) {
241 final String fileSeparator = File.separator;
242 final StringBuffer defaultFileName =
243 new StringBuffer(System.getProperty("java.home")).
244 append(fileSeparator).append("lib").append(fileSeparator).
245 append("management").append(fileSeparator).
246 append(basename);
247 return defaultFileName.toString();
248 }
249
250
251
252
253
254
255 private static String getDefaultStoreName(String basename) {
256 final String fileSeparator = File.separator;
257 final StringBuffer defaultFileName =
258 new StringBuffer(System.getProperty("test.src")).
259 append(fileSeparator).append("ssl").append(fileSeparator).
260 append(basename);
261 return defaultFileName.toString();
262 }
263
264
265
266
267
268
269
270
271
272 private ArrayList readCredentials(String passwordFileName)
273 throws IOException {
274 final Properties pws = new Properties();
275 final ArrayList result = new ArrayList();
276 final File f = new File(passwordFileName);
277 if (!f.exists()) return result;
278 FileInputStream fin = new FileInputStream(passwordFileName);
279 try {pws.load(fin);}finally{fin.close();}
280 for (Enumeration en=pws.propertyNames();en.hasMoreElements();) {
281 final String[] cred = new String[2];
282 cred[0]=(String)en.nextElement();
283 cred[1]=pws.getProperty(cred[0]);
284 result.add(cred);
285 }
286 return result;
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 public int connectAndRead(JMXServiceURL url,
315 Object[] useCredentials,
316 boolean expectConnectOk,
317 boolean expectReadOk)
318 throws IOException {
319
320 int errorCount = 0;
321
322 for (int i=0 ; i<useCredentials.length ; i++) {
323 final Map m = new HashMap();
324 final String[] credentials = (String[])useCredentials[i];
325 final String crinfo;
326 if (credentials != null) {
327 crinfo = "{"+credentials[0] + ", " + credentials[1] + "}";
328 m.put(PropertyNames.CREDENTIALS,credentials);
329 } else {
330 crinfo="no credentials";
331 }
332 log.trace("testCommunication","using credentials: " + crinfo);
333
334 final JMXConnector c;
335 try {
336 c = JMXConnectorFactory.connect(url,m);
337 } catch (IOException x ) {
338 if (expectConnectOk) {
339 final String err = "Connection failed for " + crinfo +
340 ": " + x;
341 System.out.println(err);
342 log.trace("testCommunication",err);
343 log.debug("testCommunication",x);
344 errorCount++;
345 continue;
346 } else {
347 System.out.println("Connection failed as expected for " +
348 crinfo + ": " + x);
349 continue;
350 }
351 } catch (RuntimeException x ) {
352 if (expectConnectOk) {
353 final String err = "Connection failed for " + crinfo +
354 ": " + x;
355 System.out.println(err);
356 log.trace("testCommunication",err);
357 log.debug("testCommunication",x);
358 errorCount++;
359 continue;
360 } else {
361 System.out.println("Connection failed as expected for " +
362 crinfo + ": " + x);
363 continue;
364 }
365 }
366 try {
367 MBeanServerConnection conn =
368 c.getMBeanServerConnection();
369 if (log.isDebugOn()) {
370 log.debug("testCommunication","Connection is:" + conn);
371 log.debug("testCommunication","Server domain is: " +
372 conn.getDefaultDomain());
373 }
374 final ObjectName pattern =
375 new ObjectName("java.lang:type=Memory,*");
376 final int count = listMBeans(conn,pattern,null);
377 if (count == 0)
378 throw new Exception("Expected at least one matching "+
379 "MBean for "+pattern);
380 if (expectReadOk) {
381 System.out.println("Communication succeeded " +
382 "as expected for "+
383 crinfo + ": found " + count
384 + ((count<2)?"MBean":"MBeans"));
385 } else {
386 final String err = "Expected failure didn't occur for " +
387 crinfo;
388 System.out.println(err);
389 errorCount++;
390 }
391 } catch (IOException x ) {
392 if (expectReadOk) {
393 final String err = "Communication failed with " + crinfo +
394 ": " + x;
395 System.out.println(err);
396 log.trace("testCommunication",err);
397 log.debug("testCommunication",x);
398 errorCount++;
399 continue;
400 } else {
401 System.out.println("Communication failed as expected for "+
402 crinfo + ": " + x);
403 continue;
404 }
405 } catch (RuntimeException x ) {
406 if (expectReadOk) {
407 final String err = "Communication failed with " + crinfo +
408 ": " + x;
409 System.out.println(err);
410 log.trace("testCommunication",err);
411 log.debug("testCommunication",x);
412 errorCount++;
413 continue;
414 } else {
415 System.out.println("Communication failed as expected for "+
416 crinfo + ": " + x);
417 }
418 } catch (Exception x) {
419 final String err = "Failed to read MBeans with " + crinfo +
420 ": " + x;
421 System.out.println(err);
422 log.trace("testCommunication",err);
423 log.debug("testCommunication",x);
424 errorCount++;
425 continue;
426 } finally {
427 c.close();
428 }
429 }
430 return errorCount;
431 }
432
433
434 private void setSslProperties() {
435 final String defaultKeyStore =
436 getDefaultStoreName(DefaultValues.KEYSTORE);
437 final String defaultTrustStore =
438 getDefaultStoreName(DefaultValues.TRUSTSTORE);
439
440 final String keyStore =
441 System.getProperty(PropertyNames.KEYSTORE, defaultKeyStore);
442 System.setProperty(PropertyNames.KEYSTORE,keyStore);
443 log.trace("setSslProperties",PropertyNames.KEYSTORE+"="+keyStore);
444
445 final String password =
446 System.getProperty(PropertyNames.KEYSTORE_PASSWD,
447 DefaultValues.KEYSTORE_PASSWD);
448 System.setProperty(PropertyNames.KEYSTORE_PASSWD,password);
449 log.trace("setSslProperties",
450 PropertyNames.KEYSTORE_PASSWD+"="+password);
451
452 final String trustStore =
453 System.getProperty(PropertyNames.TRUSTSTORE,
454 defaultTrustStore);
455 System.setProperty(PropertyNames.TRUSTSTORE,trustStore);
456 log.trace("setSslProperties",
457 PropertyNames.TRUSTSTORE+"="+trustStore);
458
459 final String trustword =
460 System.getProperty(PropertyNames.TRUSTSTORE_PASSWD,
461 DefaultValues.TRUSTSTORE_PASSWD);
462 System.setProperty(PropertyNames.TRUSTSTORE_PASSWD,trustword);
463 log.trace("setSslProperties",
464 PropertyNames.TRUSTSTORE_PASSWD+"="+trustword);
465 }
466
467 private void checkSslConfiguration() {
468 try {
469 final String defaultConf =
470 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME);
471 final String confname =
472 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf);
473
474 final Properties props = new Properties();
475 final File conf = new File(confname);
476 if (conf.exists()) {
477 FileInputStream fin = new FileInputStream(conf);
478 try {props.load(fin);} finally {fin.close();}
479 }
480
481
482 final String useSslStr =
483 props.getProperty(PropertyNames.USE_SSL,
484 DefaultValues.USE_SSL);
485 final boolean useSsl =
486 Boolean.valueOf(useSslStr).booleanValue();
487
488 log.debug("checkSslConfiguration",
489 PropertyNames.USE_SSL+"="+useSsl+
490 ": setting SSL");
491
492 final String useSslClientAuthStr =
493 props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
494 DefaultValues.SSL_NEED_CLIENT_AUTH);
495 final boolean useSslClientAuth =
496 Boolean.valueOf(useSslClientAuthStr).booleanValue();
497
498 log.debug("checkSslConfiguration",
499 PropertyNames.SSL_NEED_CLIENT_AUTH+"="+useSslClientAuth);
500
501
502 final String sslCipherSuites =
503 props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES);
504
505 log.debug("checkSslConfiguration",
506 PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
507 sslCipherSuites);
508
509
510 final String sslProtocols =
511 props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS);
512
513 log.debug("checkSslConfiguration",
514 PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
515 sslProtocols);
516
517 if (useSsl) setSslProperties();
518 } catch (Exception x) {
519 System.out.println("Failed to setup SSL configuration: " + x);
520 log.debug("checkSslConfiguration",x);
521 }
522 }
523
524
525
526
527
528
529
530
531
532
533
534 public void testCommunication(JMXServiceURL url)
535 throws IOException {
536
537 final String defaultConf =
538 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME);
539 final String confname =
540 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf);
541
542 final Properties props = new Properties();
543 final File conf = new File(confname);
544 if (conf.exists()) {
545 FileInputStream fin = new FileInputStream(conf);
546 try {props.load(fin);} finally {fin.close();}
547 }
548
549
550 final String useAuthenticationStr =
551 props.getProperty(PropertyNames.USE_AUTHENTICATION,
552 DefaultValues.USE_AUTHENTICATION);
553 final boolean useAuthentication =
554 Boolean.valueOf(useAuthenticationStr).booleanValue();
555
556
557 final String defaultPasswordFileName = Utils.convertPath(
558 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
559 final String passwordFileName = Utils.convertPath(
560 props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
561 defaultPasswordFileName));
562
563
564 final String defaultAccessFileName = Utils.convertPath(
565 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
566 final String accessFileName = Utils.convertPath(
567 props.getProperty(PropertyNames.ACCESS_FILE_NAME,
568 defaultAccessFileName));
569
570 if (useAuthentication) {
571 System.out.println("PasswordFileName: " + passwordFileName);
572 System.out.println("accessFileName: " + accessFileName);
573 }
574
575 final Object[] allCredentials;
576 final Object[] noCredentials = { null };
577 if (useAuthentication) {
578 final ArrayList l = readCredentials(passwordFileName);
579 if (l.size() == 0) allCredentials = null;
580 else allCredentials = l.toArray();
581 } else allCredentials = noCredentials;
582
583 int errorCount = 0;
584 if (allCredentials!=null) {
585
586
587
588 errorCount += connectAndRead(url,allCredentials,true,true);
589 } else {
590
591
592
593 final String[][] someCredentials = {
594 null,
595 { "modify", "R&D" },
596 { "measure", "QED" }
597 };
598 errorCount += connectAndRead(url,someCredentials,false,false);
599 }
600
601 if (useAuthentication && allCredentials != noCredentials) {
602
603
604
605 final String[][] badCredentials = {
606 { "bad.user", "R&D" },
607 { "measure", "bad.password" }
608 };
609 errorCount += connectAndRead(url,badCredentials,false,false);
610 }
611 if (errorCount > 0) {
612 final String err = "Test " + confname + " failed with " +
613 errorCount + " error(s)";
614 log.debug("testCommunication",err);
615 throw new RuntimeException(err);
616 }
617 }
618
619
620
621
622
623
624
625
626
627 private String testConfiguration(File file,int port) {
628
629 final String path;
630 try {
631 path=(file==null)?null:file.getCanonicalPath();
632 } catch(IOException x) {
633 final String err = "Failed to test configuration " + file +
634 ": " + x;
635 log.trace("testConfiguration",err);
636 log.debug("testConfiguration",x);
637 return err;
638 }
639 final String config = (path==null)?"Default config file":path;
640
641 System.out.println("***");
642 System.out.println("*** Testing configuration (port=" + port + "): "
643 + path);
644 System.out.println("***");
645
646 System.setProperty("com.sun.management.jmxremote.port",
647 Integer.toString(port));
648 if (path != null)
649 System.setProperty("com.sun.management.config.file", path);
650 else
651 System.getProperties().remove("com.sun.management.config.file");
652
653 log.trace("testConfiguration","com.sun.management.jmxremote.port="+port);
654 if (path != null && log.isDebugOn())
655 log.trace("testConfiguration",
656 "com.sun.management.config.file="+path);
657
658 checkSslConfiguration();
659
660 final JMXConnectorServer cs;
661 try {
662 cs = ConnectorBootstrap.initialize();
663 } catch (AgentConfigurationError x) {
664 final String err = "Failed to initialize connector:" +
665 "\n\tcom.sun.management.jmxremote.port=" + port +
666 ((path!=null)?"\n\tcom.sun.management.config.file="+path:
667 "\n\t"+config) +
668 "\n\tError is: " + x;
669 log.trace("testConfiguration",err);
670 log.debug("testConfiguration",x);
671 return err;
672 } catch (Exception x) {
673 log.debug("testConfiguration",x);
674 return x.toString();
675 }
676
677 try {
678 JMXServiceURL url =
679 new JMXServiceURL("rmi",null,0,"/jndi/rmi://localhost:"+
680 port+"/jmxrmi");
681
682 try {
683 testCommunication(url);
684 } catch (Exception x) {
685 final String err = "Failed to connect to agent {url="+url+
686 "}: " + x;
687 log.trace("testConfiguration",err);
688 log.debug("testConfiguration",x);
689 return err;
690 }
691 } catch (Exception x) {
692 final String err = "Failed to test configuration "+config+
693 ": "+x;
694 log.trace("testConfiguration",err);
695 log.debug("testConfiguration",x);
696 return err;
697 } finally {
698 try {
699 cs.stop();
700 } catch (Exception x) {
701 final String err = "Failed to terminate: "+x;
702 log.trace("testConfiguration",err);
703 log.debug("testConfiguration",x);
704 }
705 }
706 System.out.println("Configuration " + config + " successfully tested");
707 return null;
708 }
709
710
711
712
713
714
715 private String testConfigurationKo(File conf,int port) {
716 final String errStr = testConfiguration(conf,port+testPort++);
717 if (errStr == null) {
718 return "Configuration " +
719 conf + " should have failed!";
720 }
721 System.out.println("Configuration " +
722 conf + " failed as expected");
723 log.debug("runko","Error was: " + errStr);
724 return null;
725 }
726
727
728
729
730
731
732
733
734 private String testConfigurationFile(String fileName) {
735 File file = new File(fileName);
736 final String portStr = System.getProperty("rmi.port","12424");
737 final int port = Integer.parseInt(portStr);
738
739 if (fileName.endsWith("ok.properties")) {
740 return testConfiguration(file,port+testPort++);
741 }
742 if (fileName.endsWith("ko.properties")) {
743 return testConfigurationKo(file,port+testPort++);
744 }
745 return fileName +
746 ": test file suffix must be one of [ko|ok].properties";
747 }
748
749
750
751
752
753
754 public void runko() {
755 final String portStr = System.getProperty("rmi.port","12424");
756 final int port = Integer.parseInt(portStr);
757 final File[] conf = findConfigurationFilesKo();
758 if ((conf == null)||(conf.length == 0))
759 throw new RuntimeException("No configuration found");
760
761 String errStr;
762 for (int i=0;i<conf.length;i++) {
763 errStr = testConfigurationKo(conf[i],port+testPort++);
764 if (errStr != null) {
765 throw new RuntimeException(errStr);
766 }
767 }
768
769 }
770
771
772
773
774
775
776 public void runok() {
777 final String portStr = System.getProperty("rmi.port","12424");
778 final int port = Integer.parseInt(portStr);
779 final File[] conf = findConfigurationFilesOk();
780 if ((conf == null)||(conf.length == 0))
781 throw new RuntimeException("No configuration found");
782
783 String errStr;
784 for (int i=0;i<conf.length;i++) {
785 errStr = testConfiguration(conf[i],port+testPort++);
786 if (errStr != null) {
787 throw new RuntimeException(errStr);
788 }
789 }
790
791
792
793
794
795
796
797
798
799
800 }
801
802
803
804
805
806
807
808 public void run() {
809 runok();
810 runko();
811 }
812
813
814
815
816
817
818
819
820
821
822 public void run(String args[]) {
823 if (args.length == 0) {
824 run() ; return;
825 }
826 for (int i=0; i<args.length; i++) {
827 final String errStr =testConfigurationFile(args[i]);
828 if (errStr != null) {
829 throw new RuntimeException(errStr);
830 }
831 }
832 }
833
834
835
836
837
838 public static void main(String args[]) {
839 RmiBootstrapTest manager = new RmiBootstrapTest();
840 try {
841 manager.run(args);
842 } catch (RuntimeException r) {
843 System.out.println("Test Failed: "+ r.getMessage());
844 System.exit(1);
845 } catch (Throwable t) {
846 System.out.println("Test Failed: "+ t);
847 t.printStackTrace();
848 System.exit(2);
849 }
850 System.out.println("**** Test RmiBootstrap Passed ****");
851 }
852
853 }